#include "logger.h"
#ifdef ONIX
#include <onix/types.h>
#include <onix/stdio.h>
#include <onix/syscall.h>
#include <onix/string.h>
#include <onix/fs.h>
#include <onix/dsp.h>
#define DSP_DEV_FILE "/dev/dsp"
#define O_BINARY 0
#else
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define fd_t  int
typedef unsigned char u8;
#define DSP_CMD_MONO8 0x10
#define DSP_CMD_STEREO16 0x14
#define DSP_CMD_ON 0x01
#define DSP_CMD_OFF 0x02
#define DSP_CMD_VOLUME 0x04
#define ioctl(fd, cmd, arg) 
#define DSP_DEV_FILE "/dev/dsp"
#endif

static fd_t dsp = 0;
static int dev_channels;
static int dev_samplerate;
static int dev_bits_per_sample;


int pcmPlayer_init(int channels, int samplerate, int bits_per_sample) {
    int ret = 0;
    dsp = open(DSP_DEV_FILE, O_WRONLY | O_BINARY, 0);
    if(dsp < 0) {
        elog("Can't open %s\n", DSP_DEV_FILE);
        ret = -1;
        goto rollback;
    }
    if(samplerate == 48000) {
        ilog("Not support sample %d Hz, will use 44100 Hz\n", samplerate);
        samplerate = 44100;
    }

    if (samplerate != 44100)
    {
        elog("Not support sample %d Hz.\n", samplerate);
        ret = -2;
        goto rollback;
    }

    u8 mode;

    if (bits_per_sample == 8 && channels == 1)
    {
        mode = DSP_CMD_MONO8;
    }
    else if (bits_per_sample == 16 && channels == 2)
    {
        mode = DSP_CMD_STEREO16;
    }
    else
    {
        elog("Cannot play channels %d and bits %d\n",
               channels,
               bits_per_sample);
        ret = -3;
        goto rollback;
    }


    ioctl(dsp, DSP_CMD_ON, 0);
    ioctl(dsp, mode, 0);
    ioctl(dsp, DSP_CMD_VOLUME, 0xff);


    dev_channels = channels;
    dev_samplerate = samplerate;
    dev_bits_per_sample = bits_per_sample;
    
rollback:
    if (ret < 0 && dsp > 0)
    {
        ioctl(dsp, DSP_CMD_OFF, 0);
        close(dsp);
    }
    if(ret < 0) {
        elog("dsp init failed\n");
    } else {
        ilog("dsp init success\n");
    }
    return ret;    
}

int pcmPlayer_getParams(int *channels, int *samplerate, int *bits_per_sample) {
    if(dsp<=0) {
        elog("dsp is NULL\n");
        return -1;
    }
    if(!channels || !samplerate || !bits_per_sample) {
        elog("arg channels, samplerate or bits_per_sample is NULL\n");
        return -1;
    }
    *channels = dev_channels;
    *samplerate = dev_samplerate;
    *bits_per_sample = dev_bits_per_sample;
    return 0;
}

int pcmPlayer_write(void *pcm_data, int size) {
    if(!dsp) {
        elog("dsp is NULL\n");
        return -1;
    }
    int len = write(dsp, pcm_data, size);
    return len;
}


int pcmPlayer_deinit() {
    if(!dsp) {
        elog("dsp is NULL\n");
        return -1;
    }
    //flush(dsp);
    ioctl(dsp, DSP_CMD_OFF, 0);
    close(dsp);
    return 0;
}